home *** CD-ROM | disk | FTP | other *** search
/ Games of Daze / Infomagic - Games of Daze (Summer 1995) (Disc 1 of 2).iso / x2ftp / msdos / ai / fuzzy / prover.b < prev    next >
Text File  |  1986-11-29  |  38KB  |  973 lines

  1. -------------------------------------------------------------------------------
  2. --                                                                           --
  3. --  Library Unit:  Prover -- Prove or process user requests                  --
  4. --                                                                           --
  5. --  Author:  Bradley L. Richards                                             --
  6. --                                                                           --
  7. --     Version     Date     Notes . . .                                      --
  8. --    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -    --
  9. --       1.0    - - - - -   Never existed.  First version implemented after  --
  10. --                            Parser et al reached version 2.0               --
  11. --       2.0    20 Jun 86   Initial Version                                  --
  12. --       2.05   13 Jul 86   Split into separate spec and package files       --
  13. --       2.1    21 Jul 86   Demonstration version -- initial predicates      --
  14. --                            implemented; initial debugging completed       --
  15. --       2.2    28 Jul 86   Initial operational version -- 20 predicates     --
  16. --                            implemented, plus lots of squashed bugs        --
  17. --       2.3    19 Aug 86   Use AVL trees for rule_base, add many reserved   --
  18. --                            predicates, and split output routines into     --
  19. --                            package print_stuff.                           --
  20. --       2.4    31 Aug 86   Split do_reserved into separate file             --
  21. --       2.5     1 Sep 86   Split execute into separate file                 --
  22. --       3.0    10 Oct 86   Final thesis product                             --
  23. --    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -    --
  24. --                                                                           --
  25. --  Description:  This package contains only one visible routine:  Prove.    --
  26. --       Prove is nothing but a shell for the primary resolution routine     --
  27. --       Seek.  After Proveand the AVL comparison routines, all routines     --
  28. --       appear in alphabetical order.                                       --
  29. --                                                                           --
  30. --       Seek (and many other routines herein) is a recursive routine.  It   --
  31. --       accepts an initial goal_tree from Prove and resolves a single       --
  32. --       predicate.  It then passes the revised goal_tree (possibly          --
  33. --       heavily modified due to new goals, etc.) to a recursive call of     --
  34. --       itself.                                                             --
  35. --                                                                           --
  36. --       Other important routines:  Unify attempts to unify two predicates   --
  37. --       and their arguments, creating bindings as necessary.  Do_reserved   --
  38. --       processes reserved predicates.  Execute executes operators of all   --
  39. --       types (arithmetic, comparison, logical).                            --
  40. --                                                                           --
  41. --            Most of the routines in this package are recursive.  In order  --
  42. --       to successfully backtrack, it is critical that each time a routine  --
  43. --       is called it creates a local copy of anything it plans to modify    --
  44. --       Two important examples are the goal_tree and the binding list.      --
  45. --                                                                           --
  46. -------------------------------------------------------------------------------
  47. --                                                                           --
  48. --                            Package Body                                   --
  49. --                                                                           --
  50. -------------------------------------------------------------------------------
  51.  
  52. package body prover is
  53.  
  54.     aborting, cutting, trace_mode : boolean := false;
  55.     cutting_level : integer;
  56.     current_truth : float;
  57.     quote : constant boolean := true;
  58.     no_quote : constant boolean := false;
  59.     threshold : fuzzy_values;
  60.     rule_base : tree_ptr := init_tree;
  61.  
  62.     --
  63.     --  Specifications for all procedures.  Forward referencing all procedures
  64.     --  saves the headache of figuring out which ones need forward references.
  65.     --
  66.     procedure find_bond(var_name : name_ptr; var_level : natural;
  67.             bindings : binding_list; value : out argument_ptr;
  68.             value_level : out integer);
  69.     procedure find_first(goal_tree, modify, place : in out AST_ptr;
  70.                  bindings : in out binding_list;
  71.              res_level : in out natural; failed : in out boolean);
  72.     procedure insert(goal_tree, replace : in out AST_ptr;
  73.              modify, new_goals : in AST_ptr; level : natural);
  74.     procedure lookup(arg_node : AST_ptr; level : natural;
  75.              bindings : binding_list; value_out : out argument_ptr;
  76.              level_out : out integer);
  77.     procedure lookup(args : argument_ptr; level : natural;
  78.              bindings : binding_list; value_out : out argument_ptr;
  79.              level_out : out integer );
  80.     procedure release(bindings, stop : binding_list);
  81.     function seek(goal_tree_in : in AST_ptr; bindings_in : binding_list;
  82.           level : natural) return boolean;
  83.     procedure start_prover;
  84.     procedure stop_prover;
  85.     procedure trace(set_trace : boolean);
  86.     procedure trace_entry(pred, goal_tree : AST_ptr; bindings : binding_list;
  87.               level, res_level : natural; failed : in out boolean);
  88.     procedure trace_exit(pred, goal_tree : AST_ptr; bindings : binding_list;
  89.              level, res_level : natural; failed : in out boolean);
  90.     procedure trace_fail(pred, goal_tree : AST_ptr; bindings : binding_list;
  91.              level, res_level : natural; failed : in out boolean);
  92.     procedure trace_print(goal_tree : AST_ptr; bindings : binding_list;
  93.               failed : in out boolean);
  94.     procedure unify(predicate1, predicate2 : AST_ptr;
  95.             res_level, level : natural; bindings : in out binding_list;
  96.             unified : out boolean);
  97.     procedure unify_list(predicate1, predicate2 : p_list_ptr;
  98.                  res_level, level : natural;
  99.                  bindings : in out binding_list; unified : out boolean);
  100.     procedure unify_arg(arg_node1, arg_node2 : AST_ptr;
  101.             res_level, level : natural;
  102.             bindings : in out binding_list; unified : out boolean);
  103.     procedure unify_arg(arg1, arg2 : argument_ptr;
  104.             res_level, level : natural;
  105.                 bindings : in out binding_list; unified : out boolean);
  106.  
  107.     --
  108.     --  Forward references for separate routines.
  109.     --
  110.     --     Do_reserved is in file do_reservedB.a
  111.     --
  112.     procedure do_reserved(pred, goal_tree : AST_ptr; result_node : out AST_ptr;
  113.               bindings : in out binding_list; level : natural;
  114.               failed : in out boolean);
  115.  
  116.     --
  117.     --     Execute is in file executeB.a
  118.     --
  119.     procedure execute(operator : in out AST_ptr; bindings : in out binding_list;
  120.               level : natural; failed : in out boolean);
  121.  
  122.     --
  123.     --     These print routines are in file print_stuffB.a
  124.     --
  125.     procedure print_argument( argument : argument_ptr; bindings : binding_list;
  126.                   level : natural; quotes : boolean );
  127.     procedure print_arguments( in_arguments : argument_ptr;
  128.                    bindings : binding_list; level : natural;
  129.                    quotes : boolean );
  130.     procedure print_AST( ast_node : AST_ptr; indent : integer );
  131.     procedure print_bin_op( operator : binary_operators );
  132.     procedure put_bin_op( operator : binary_operators );
  133.     procedure print_bindings(bindings_in : binding_list; indent : natural );
  134.     procedure print_clause( clause : AST_ptr );
  135.     procedure print_list( in_list : p_list_ptr; bindings : binding_list;
  136.               level : natural; quotes : boolean );
  137.     procedure print_list_tail( in_list : p_list_ptr; bindings : binding_list;
  138.               level : natural; quotes : boolean );
  139.     procedure print_predicate( node : AST_ptr; indent : natural;
  140.                    bindings : binding_list;
  141.                    level : natural );
  142.     procedure print_reserved( node : AST_ptr; indent : natural;
  143.                   bindings : binding_list;
  144.                   level : natural );
  145.     procedure put_reserved( reserved_predicate : reserved_predicates );
  146.     procedure print_result( bindings_in : binding_list;
  147.                 done : out boolean);
  148.     procedure print_un_op(operator : unary_operators);
  149.     procedure put_un_op(operator : unary_operators);
  150.     procedure space(number : natural);
  151.  
  152.  
  153.     --
  154.     --  Routines for processing reserved words are maintained in a separate
  155.     --  file.  They are not kept as a separate package because their processing
  156.     --  really is an implicit part of the Prover's task.
  157.     --
  158.     procedure do_reserved(pred, goal_tree : AST_ptr; result_node : out AST_ptr;
  159.               bindings : in out binding_list; level : natural;
  160.               failed : in out boolean) is separate;
  161.  
  162.     --
  163.     --  Routines for executing operators are kept in a separate file.  The real
  164.     --  reason for all these separate files is to keep individual file size
  165.     --  (and compilation time) down, and to enhance readability of the listings.
  166.     --
  167.     procedure execute(operator : in out AST_ptr; bindings : in out binding_list;
  168.               level : natural; failed : in out boolean) is separate;
  169.  
  170.     --
  171.     --  Print routines are maintained in a separate file
  172.     --
  173.     procedure print_argument( argument : argument_ptr; bindings : binding_list;
  174.                   level : natural; quotes : boolean ) is separate;
  175.     procedure print_arguments( in_arguments : argument_ptr;
  176.                    bindings : binding_list; level : natural;
  177.                    quotes : boolean ) is separate;
  178.     procedure print_AST( ast_node : AST_ptr; indent : integer ) is separate;
  179.     procedure print_bin_op( operator : binary_operators ) is separate;
  180.     procedure put_bin_op( operator : binary_operators ) is separate;
  181.     procedure print_bindings(bindings_in : binding_list;
  182.                  indent : natural ) is separate;
  183.     procedure print_clause( clause : AST_ptr ) is separate;
  184.     procedure print_list( in_list : p_list_ptr; bindings : binding_list;
  185.               level : natural; quotes : boolean ) is separate;
  186.     procedure print_list_tail( in_list : p_list_ptr; bindings : binding_list;
  187.               level : natural; quotes : boolean ) is separate;
  188.     procedure print_predicate( node : AST_ptr; indent : natural;
  189.                    bindings : binding_list;
  190.                    level : natural ) is separate;
  191.     procedure print_reserved( node : AST_ptr; indent : natural;
  192.                   bindings : binding_list;
  193.                   level : natural ) is separate;
  194.     procedure put_reserved(reserved_predicate : reserved_predicates) is separate;
  195.     procedure print_result( bindings_in : binding_list;
  196.                 done : out boolean) is separate;
  197.     procedure print_un_op(operator : unary_operators) is separate;
  198.     procedure put_un_op(operator : unary_operators) is separate;
  199.     procedure space(number : natural) is separate;
  200.  
  201. --
  202. --  Procedures for use by the AVL package when comparing clauses
  203. --
  204. function clause_equal( a, b : AST_ptr ) return boolean is
  205.   begin
  206.     return(a.head.name.name = b.head.name.name);
  207.   end clause_equal;
  208.  
  209. function clause_less_than( a, b : AST_ptr ) return boolean is
  210.   begin
  211.     return(a.head.name.name < b.head.name.name);
  212.   end clause_less_than;
  213.  
  214.  
  215. --
  216. --  Prove -- accept a goal from the calling unit and process it.
  217. --
  218. procedure prove( goal : in AST_ptr ) is
  219.   begin
  220.     --
  221.     --  goal must be an AST_ptr which points to a predicate or reserved
  222.     --  predicate of some sort.  Reserved predicates require special
  223.     --  processing of some sort.
  224.     --
  225.     start_prover;
  226.     if seek(goal, null, 1) then
  227.       put_line("yes");
  228.     else
  229.       put_line("no");
  230.     end if;
  231.     stop_prover;
  232.   end prove;
  233.  
  234.  
  235. --
  236. --  Find_bond -- Given a variable name and its level, return what it is
  237. --               bound to.  If it is not bound, return null.
  238. --
  239. procedure find_bond( var_name : name_ptr; var_level : natural;
  240.              bindings : binding_list;
  241.              value : out argument_ptr; value_level : out integer ) is
  242.     binding : binding_list := bindings;
  243.   begin
  244.     while binding /= null loop
  245.       if binding.name.name = var_name.name and binding.level = var_level then
  246.     --
  247.     --  we've found the binding
  248.     --
  249.     value := binding.value;
  250.     value_level := binding.value_level;
  251.     exit;
  252.       end if;
  253.       binding := binding.next_binding;
  254.     end loop;
  255.     if binding = null then -- not found
  256.       value := null;
  257.       value_level := 0;
  258.     end if;
  259.   end find_bond;
  260.  
  261.  
  262. --
  263. --  Find_first -- Given a goal_tree, do a pre-order walk through it looking
  264. --                for the first predicate which still needs resolved.  When
  265. --                walking the tree, execute any operators which are ready
  266. --                (i.e. have their operands defined).
  267. --                     Comparison and arithmetic operators will always be
  268. --                executed when found.  Logic operators will be executed only
  269. --                if their operands have been resolved to fuzzy_value nodes.
  270. --                     On return, "place" points to the unresolved
  271. --                predicate if one was found.  If this predicate is not at
  272. --                the top of the tree then "modify" points to its parent.
  273. --
  274. procedure find_first(goal_tree, modify, place : in out AST_ptr;
  275.              bindings : in out binding_list; res_level : in out natural;
  276.              failed : in out boolean ) is
  277.     temp : AST_ptr;
  278.     temp_level : natural;
  279.   begin
  280.     if goal_tree.node_type = fuzzy_value then
  281.       current_truth := goal_tree.fuzzy_num;
  282.       place := null;  -- at the bottom of the tree
  283.     elsif goal_tree.node_type = threshold_marker then
  284.       current_truth := goal_tree.fuzzy_value;
  285.       place := null;  -- at the bottom of the tree
  286.     elsif (goal_tree.node_type = predicate) or
  287.       (goal_tree.node_type = reserved_predicate) then
  288.       place := goal_tree;
  289.       modify := null;
  290.     elsif goal_tree.node_type = unary_operator then
  291.       place := null;
  292.       if goal_tree.unary_op = rw_not then -- a logic operator
  293.         find_first(goal_tree.operand,modify,place, bindings, res_level, failed);
  294.       end if;
  295.       if (place = null) and (not failed) then -- operand is ready, so execute
  296.         execute(goal_tree, bindings, res_level, failed);
  297.       elsif (modify = null) and (not failed) then -- unresolved predicate is the
  298.                           -- child of "goal_tree"
  299.         modify := goal_tree;
  300.       end if; -- otherwise just pass back what was found lower in goal_tree
  301.     elsif goal_tree.node_type = binary_operator then
  302.     --
  303.     --  Don't look below comparison or arithmetic operators
  304.     --
  305.     place := null;
  306.     if goal_tree.binary_op in binary_logic_operators then
  307.           find_first(goal_tree.left_operand,modify,place,bindings,res_level,
  308.              failed);
  309.     end if;
  310.         if (place = null) and (not failed) then -- left operand is resolved
  311.       if goal_tree.binary_op in binary_logic_operators then
  312.         find_first(goal_tree.right_operand,modify,place,bindings,res_level,
  313.                failed);
  314.       end if;
  315.       if (place = null) and (not failed) then -- both operands resolved
  316.         execute(goal_tree, bindings, res_level, failed);
  317.       elsif (modify = null) and (not failed) then
  318.         modify := goal_tree;
  319.       end if;
  320.     elsif (modify = null) and (not failed) then
  321.       modify := goal_tree;
  322.     end if;
  323.     elsif goal_tree.node_type = resolution_marker then
  324.       temp_level := goal_tree.level;
  325.       threshold := goal_tree.old_threshold;
  326.       find_first(goal_tree.subgoals, modify, place, bindings, temp_level, failed);
  327.       if (place = null) and (not failed) then -- throw away the marker node
  328.     threshold := goal_tree.old_threshold;  -- but first restore threshold
  329.     temp := goal_tree;
  330.     goal_tree := goal_tree.subgoals;
  331.     release(temp, temp.subgoals);
  332.     if goal_tree.node_type = threshold_marker then
  333.       --  Cannot allow upward propogation of thresholds
  334.       temp := new AST'(fuzzy_value, goal_tree.fuzzy_value);
  335.       release(goal_tree, null);
  336.       goal_tree := temp;
  337.     end if;
  338.       elsif (not failed) then
  339.     if goal_tree.level /= temp_level then -- found a new level lower down
  340.       res_level := temp_level;
  341.     else -- this marker node is the lowest one
  342.       res_level := goal_tree.level;
  343.     end if;
  344.     if modify = null then
  345.       modify := goal_tree;
  346.     end if;
  347.       end if;
  348.     else -- we're apparently at a leaf node in the depths of the tree
  349.       place := null;
  350.     end if;
  351.   end find_first;
  352.  
  353.  
  354. procedure insert( goal_tree, replace : in out AST_ptr;
  355.           modify, new_goals : in AST_ptr;
  356.           level : natural) is
  357.     goals : AST_ptr := new AST'(resolution_marker, level, threshold, new_goals);
  358.   begin
  359.     if modify = null then -- modify top of tree
  360.       goal_tree := goals;
  361.     elsif modify.node_type = unary_operator then
  362.       modify.operand := goals;
  363.     elsif modify.node_type = binary_operator then
  364.       if modify.left_operand = replace then
  365.     modify.left_operand := goals;
  366.       else -- right_operand
  367.     modify.right_operand := goals;
  368.       end if;
  369.     elsif modify.node_type = resolution_marker then
  370.       modify.subgoals := goals;
  371.     else
  372.       error(no_pointer,"insert:  Modify points to invalid node type");
  373.     end if;
  374.     replace := goals;
  375.   end insert;
  376.  
  377.  
  378. procedure lookup( arg_node : AST_ptr; level : natural;
  379.           bindings : binding_list; value_out : out argument_ptr;
  380.           level_out : out integer) is
  381.     template : constant argument_ptr := new argument'(variable, null, null);
  382.   begin
  383.     case arg_node.node_type is
  384.       when character_lit =>
  385.     value_out := new argument'(character_lit, null, arg_node.char);
  386.     level_out := level;
  387.       when float_num =>
  388.     value_out := new argument'(float_num, null, arg_node.fp_num);
  389.     level_out := level;
  390.       when integer_num =>
  391.     value_out := new argument'(integer_num, null, arg_node.int_num);
  392.     level_out := level;
  393.       when predicate =>
  394.     value_out := new argument'(predicate, null, arg_node.name,
  395.                    arg_node.p_arguments);
  396.     level_out := level;
  397.       when variable =>
  398.     template.v_name := arg_node.var_name;
  399.     lookup(template, level, bindings, value_out, level_out);
  400.       when fuzzy_value =>
  401.     value_out := new argument'(float_num, null, arg_node.fuzzy_num);
  402.     level_out := level;
  403.       when others =>
  404.     error(no_pointer, "invalid node to lookup");
  405.       end case;
  406.   end lookup;
  407.       
  408.  
  409. procedure lookup( args : argument_ptr; level : natural;
  410.           bindings : binding_list; value_out : out argument_ptr;
  411.           level_out : out integer) is
  412.     value : argument_ptr;
  413.     value_level : natural;
  414.   begin
  415.     if args.is_a /= variable then
  416.       value_out := args;
  417.       level_out := level;
  418.     else -- it is a variable
  419.       if args.v_name = null then -- it's anonymous
  420.     value_out := args;
  421.     level_out := level;
  422.       else
  423.         find_bond(args.v_name, level, bindings, value, value_level);
  424.         if value /= null then -- it does have a binding, so go look IT up
  425.       lookup(value, value_level, bindings, value_out, level_out);
  426.         else
  427.       value_out := args;
  428.       level_out := level;
  429.         end if;
  430.       end if;
  431.     end if;
  432.   end lookup;
  433.  
  434.  
  435. --
  436. --  Release -- Return memory to the system using UNCHECKED_DEALLOCATION.
  437. --             Release routines are necessary since the current Verdix
  438. --             Compiler does not include an automatic garbage collector.
  439. --             Releases all items within the structure UP TO the "stop"
  440. --             value.
  441. --
  442. procedure release(bindings, stop : binding_list) is
  443.  
  444.     ptr : binding_list := bindings;
  445.     rid : binding_list;
  446.  
  447.   begin
  448.  
  449.     while ptr /= stop loop
  450.       rid := ptr;
  451.       ptr := ptr.next_binding;
  452.       free_binding(rid);
  453.     end loop;
  454.  
  455.   end release;
  456.  
  457.  
  458. --
  459. --  Seek -- Attempt to justify the goals based on the rule_base.  This is
  460. --          a highly recursive routine.  Backtracking is accomplished by
  461. --          returning with the value false.  Returning with the value true
  462. --          indicates a successful resolution.
  463. --
  464. function seek(goal_tree_in : in AST_ptr; bindings_in : binding_list;
  465.                           level : natural) return boolean is
  466.     db_ptr : AST_ptr;
  467.     modify, pred, replace : AST_ptr := null;
  468.     goal_tree, new_goals : AST_ptr;
  469.     bindings_ff : binding_list := bindings_in;
  470.     bindings : binding_list;
  471.     been_here, done, failed : boolean := false;
  472.     is_NOT, unified : boolean;
  473.     res_level : natural := 0;
  474.     template : constant AST_ptr := new AST'(implication,
  475.           new AST'(predicate, null, null), null, null, null);
  476.  
  477.     function replicate (in_tree : AST_ptr) return AST_ptr is
  478.       begin
  479.     if in_tree = null then
  480.       return null;
  481.     else
  482.       case in_tree.node_type is
  483.         when implication =>
  484.           return new AST'(implication, replicate(in_tree.head),
  485.                   replicate(in_tree.tail), in_tree.prev,
  486.                   in_tree.next);
  487.         when binary_operator =>
  488.           return new AST'(binary_operator, in_tree.binary_op,
  489.                   replicate(in_tree.left_operand),
  490.                   replicate(in_tree.right_operand));
  491.         when unary_operator =>
  492.           return new AST'(unary_operator, in_tree.unary_op,
  493.                   replicate(in_tree.operand));
  494.         when resolution_marker =>
  495.           return new AST'(resolution_marker, in_tree.level,
  496.                   in_tree.old_threshold, replicate(in_tree.subgoals));
  497.         when others =>
  498.           return new AST'(in_tree.all);
  499.       end case;
  500.     end if;
  501.       end replicate;
  502.  
  503.  
  504.   begin -- seek
  505.     --
  506.     --  Since we plan to modify the goal tree, we need our own local copy
  507.     --  to allow successful backtracking
  508.     --
  509.     goal_tree := replicate(goal_tree_in);
  510.     --
  511.     --  Do a pre-order walk through the goal-tree looking for a predicate to
  512.     --  resolve.  Enroute execute any operators we can.  In some cases such
  513.     --  as "=" this may modify the bindings.  On return, predicate points to
  514.     --  the predicate needing resolution, and modify points to its parent
  515.     --
  516.     find_first(goal_tree, modify, pred, bindings_ff, res_level, failed);
  517.     --
  518.     --  executing comparators may have changed bindings, so save the _ff version
  519.     --
  520.     bindings := bindings_ff;
  521.     if current_truth < threshold then
  522.       failed := true;
  523.     end if;
  524.     if (pred = null) and (not failed) then -- no more unresolved predicates
  525.       if goal_tree.node_type = fuzzy_value then
  526.         print_result(bindings, done);
  527.       else
  528.     raise prover_error;
  529.       end if;
  530.     elsif not failed then
  531.       replace := pred;
  532.       while (not done) and (not failed) loop
  533.     if trace_mode then
  534.       trace_entry(pred, goal_tree, bindings, level, res_level, failed);
  535.       exit when aborting;
  536.     end if;
  537.     if pred.node_type = reserved_predicate then
  538.       if been_here then
  539.         failed := true;  -- can never resatisfy built-in predicates
  540.         if pred.predicate = cut then
  541.           cutting := true;
  542.           cutting_level := res_level;
  543.         end if;
  544.       else
  545.         do_reserved(pred,goal_tree, new_goals, bindings, res_level, failed);
  546.         if pred.predicate /= rw_repeat then
  547.           been_here := true;
  548.         end if;
  549.       end if;
  550.     else
  551.       --
  552.       --  Search through the database for something which unifies with it
  553.       --
  554.       if not been_here then
  555.         template.head.name := pred.name;
  556.         db_ptr := fetch_node(rule_base, template);
  557.         been_here := true;
  558.       end if;
  559.       while db_ptr /= null loop
  560.         unify(pred, db_ptr.head, res_level, level, bindings, unified);
  561.         exit when unified;
  562.         --
  563.         --  We may have made a few bindings before running into a dead end
  564.         --
  565.         release(bindings, bindings_ff);
  566.         bindings := bindings_ff;
  567.         db_ptr := db_ptr.next;
  568.       end loop;
  569.       if db_ptr = null then -- we failed to unify it with anything
  570.         failed := true;
  571.       else
  572.         current_truth := 1.0; -- successful resolution
  573.         new_goals := db_ptr.tail;
  574.         db_ptr := db_ptr.next; -- advance to next in case of backtracking
  575.       end if;
  576.     end if;
  577.     --
  578.     --  Failed requires special logic.  In Prolog the NOT operator affects
  579.     --  its operand immediately; e.g. if the operand can be resolved, NOT
  580.     --  makes it appear as though it could not be resolved.  With the fuzzy
  581.     --  values in Fuzzy Prolog this becomes a significant exception to the
  582.     --  logic.  To maintain compatibility with Prolog, Seek is modified to
  583.     --  process predicates who parent is a NOT specially.  If the parent
  584.     --  fails, the result becomes fuzzy(0.0) for a single pass through the
  585.     --  logic (the while loop catches the failure on the next pass).  If the
  586.     --  child succeeds with resolution (or do_reserved), the complement of
  587.     --  the current truth value is immediately compared with the threshold
  588.     --  to see if processing should be allowed to continue.
  589.     --
  590.     is_NOT := (modify /= null) and then
  591.              (modify.node_type = unary_operator) and then
  592.              (modify.unary_op = rw_not);
  593.     if (failed and (not is_NOT)) or
  594.        ((not failed) and then is_NOT and then
  595.         (pred.node_type = reserved_predicate) and then
  596.         (pred.predicate /= rw_call)) then
  597.       done := false;
  598.       if trace_mode then
  599.         if failed then
  600.           trace_fail(pred, goal_tree, bindings, level, res_level, failed );
  601.         else
  602.           trace_exit(pred, goal_tree, bindings, level, res_level, failed );
  603.         end if;
  604.       end if;
  605.       exit;
  606.     else
  607.       if failed then -- we are underneath a NOT operator
  608.         current_truth := 1.0; -- like successful resolution
  609.         new_goals := new AST'(fuzzy_value, 0.0); -- which NOT will invert
  610.       end if;
  611.       --
  612.       --  Insert the new goals associated with this beast into the goal tree
  613.       --
  614.       insert(goal_tree, replace, modify, new_goals, level);
  615.       done := seek(goal_tree, bindings, (level+1));
  616.       exit when aborting;
  617.       if trace_mode then
  618.         if failed then
  619.           trace_fail(pred, goal_tree, bindings, level, res_level, failed );
  620.         else
  621.           trace_exit(pred, goal_tree, bindings, level, res_level, failed );
  622.         end if;
  623.         exit when aborting;
  624.         --
  625.         --  restore the goal tree so that trace_entry prints meaningful info
  626.         --
  627.         insert(goal_tree, replace, modify, pred, level);
  628.       end if;
  629.       if pred.node_type = reserved_predicate then
  630.         --
  631.         --  new_goals was constructed, and should now be discarded
  632.         --
  633.         if trace_mode then
  634.           release(new_goals, null); -- partial release
  635.         else
  636.           release(replace, null); -- full release
  637.         end if;
  638.       end if;
  639.           --
  640.           --  We've appended bindings to the front of the binding list.  Release
  641.           --  these, but don't release any that were in bindings_ff
  642.           --
  643.           release(bindings, bindings_ff);
  644.       if cutting then
  645.         if res_level >= cutting_level then -- yes, it means us
  646.           exit;
  647.         else
  648.           cutting := false;
  649.           exit;  -- can't resatisfy this predicate
  650.         end if;
  651.       end if;
  652.       bindings := bindings_ff;
  653.     end if;
  654.       end loop;
  655.     end if;
  656.     --
  657.     --  The goal_tree is drastically altered as predicates are resolved and
  658.     --  operators executed.  Hence the need for our own local copy of the
  659.     --  complete AST structure which is the goal_tree.  However, replicate
  660.     --  does not copy any structure referenced by the goal_tree (e.g. string
  661.     --  records and argument lists); rather it just points to the existing
  662.     --  ones.  It is important that these items not be released when the local
  663.     --  copy of the goal tree is discarded.  Also, when adding goals to the
  664.     --  tree as a result of resolution, rather than making an immediate copy
  665.     --  of these, a pointer into the rule_base is used.  It would be disastrous
  666.     --  to destroy part of the rule base, so this part of the local goal_tree
  667.     --  (new_goals and lower) must not be released.
  668.     release(goal_tree, new_goals);  -- we're done with our goal_tree
  669.     release(pred, null);  -- a divorced segment of our goal_tree
  670.     --
  671.     --  Release all bindings created by this routine, but don't touch any
  672.     --  that were present when we were called
  673.     --
  674.     release(bindings, bindings_in);
  675.     return done;
  676.   end seek;
  677.  
  678.  
  679. procedure start_prover is
  680.   begin
  681.     current_truth := 1.0;
  682.     threshold := 0.1; -- default value
  683.     cutting := false;
  684.     aborting := false;
  685.   end start_prover;
  686.  
  687. procedure stop_prover is
  688.   begin
  689.     null;
  690.   end stop_prover;
  691.  
  692. procedure trace( set_trace : boolean ) is
  693.   begin
  694.     trace_mode := set_trace;
  695.   end trace;
  696.  
  697.  
  698. procedure trace_entry( pred, goal_tree : AST_ptr; bindings : binding_list ;
  699.                level, res_level : natural; failed : in out boolean ) is
  700.     value : float;
  701.   begin
  702.     new_line;
  703.     put(level,4);
  704.     put('('); put(res_level,4); put(')'); put(":  ");
  705.     put("Entering ");
  706.     if pred.node_type = predicate then
  707.       print_predicate(pred, 0, bindings, res_level);
  708.     else -- reserved_predicate
  709.       print_reserved(pred, 0, bindings, res_level);
  710.     end if;
  711.     space(13);
  712.     put("Current truth/threshold:  ");
  713.     put(current_truth); put('/'); put(threshold);
  714.     new_line;
  715.     trace_print(goal_tree, bindings, failed);
  716.   end trace_entry;
  717.  
  718. procedure trace_exit( pred, goal_tree : AST_ptr; bindings : binding_list ;
  719.               level, res_level : natural; failed : in out boolean ) is
  720.     value : float;
  721.   begin
  722.     put(level,4);
  723.     put('('); put(res_level,4); put(')'); put(":  ");
  724.     put("Exiting ");
  725.     if pred.node_type = predicate then
  726.       print_predicate(pred, 0, bindings, res_level);
  727.     else -- reserved_predicate
  728.       print_reserved(pred, 0, bindings, res_level);
  729.     end if;
  730.     space(13);
  731.     put("Current truth/threshold:  ");
  732.     put(current_truth); put('/'); put(threshold);
  733.     new_line;
  734.     trace_print(goal_tree, bindings, failed);
  735.   end trace_exit;
  736.  
  737.  
  738. procedure trace_fail( pred, goal_tree : AST_ptr; bindings : binding_list ;
  739.               level, res_level : natural; failed : in out boolean ) is
  740.   begin
  741.     put(level,4);
  742.     put('('); put(res_level,4); put(')'); put(":  ");
  743.     put("Fail ");
  744.     if pred.node_type = predicate then
  745.       print_predicate(pred, 0, bindings, res_level);
  746.     else -- reserved_predicate
  747.       print_reserved(pred, 0, bindings, res_level);
  748.     end if;
  749.     space(13);
  750.     put("Current truth/threshold:  ");
  751.     put(current_truth); put('/'); put(threshold);
  752.     new_line;
  753.     trace_print(goal_tree, bindings, failed);
  754.   end trace_fail;
  755.  
  756.  
  757. procedure trace_print( goal_tree : AST_ptr; bindings : binding_list;
  758.             failed : in out boolean ) is
  759.     ans : string(1..70);
  760.     length : integer;
  761.   begin
  762.     loop
  763.       put("Trace -> ");
  764.       get_line(ans, length);
  765.       if length = 0 then
  766.     exit;
  767.       end if;
  768.       case ans(1) is
  769.     when ' ' | 'C' | 'c'  =>
  770.         exit;
  771.     when 'A' | 'a'  =>
  772.       aborting := true;
  773.       failed := true;
  774.       exit;
  775.     when 'F' | 'f'  =>
  776.       failed := true;
  777.       exit;
  778.     when 'B' | 'b'  =>
  779.       put_line("Current bindings are");
  780.       print_bindings(bindings, 4);
  781.     when 'G' | 'g'  =>
  782.       put_line("Current goal tree is");
  783.       print_AST(goal_tree, 4);
  784.     when 'H' | 'h' | '?'  =>
  785.       put_line("Trace commands are");
  786.       put_line("  <c/r>, <space>, or continue:  continue execution");
  787.       put_line("  abort:  abort current proof and return to prompt");
  788.       put_line("  bindings:  print current binding list");
  789.       put_line("  fail:  fail current goal and backtrack");
  790.       put_line("  goals:  print current goal tree");
  791.       put_line("  help or ?:  print this menu");
  792.       put_line("  notrace:  turn off trace mode");
  793.       put_line("  truth:  print current truth value and threshold");
  794.       new_line;
  795.     when 'N' | 'n'  =>
  796.       trace_mode := false;
  797.       exit;
  798.     when 'T' | 't'  =>
  799.       put("Current truth/threshold:  ");
  800.       put(current_truth); put('/'); put(threshold);
  801.       new_line;
  802.     when others  =>
  803.       put_line("Invalid command; enter ? for help");
  804.       end case;
  805.     end loop;
  806.   end trace_print;
  807.  
  808.  
  809. procedure unify(predicate1, predicate2 : AST_ptr; res_level, level : natural;
  810.         bindings : in out binding_list; unified : out boolean) is
  811.     args1 : argument_ptr := predicate1.p_arguments;
  812.     args2 : argument_ptr := predicate2.p_arguments;
  813.     value1, value2 : argument_ptr;
  814.     level1, level2 : natural;
  815.     matched : boolean := true;
  816.   begin
  817.     if predicate1.name.name = predicate2.name.name then -- there's a chance
  818.       while (args1 /= null) and matched loop
  819.     if args2 = null then
  820.       matched := false;
  821.     else
  822.       unify_arg(args1, args2, res_level, level, bindings, matched);
  823.       args1 := args1.next_arg;
  824.       args2 := args2.next_arg;
  825.     end if;
  826.       end loop;
  827.       if args2 /= null then
  828.     matched := false;
  829.       end if;
  830.       unified := matched;
  831.     end if;
  832.   end unify;
  833.  
  834.  
  835. procedure unify_list(predicate1, predicate2 : p_list_ptr; res_level, level : natural;
  836.              bindings : in out binding_list; unified : out boolean) is
  837.     list1 : p_list_ptr := predicate1;
  838.     list2 : p_list_ptr := predicate2;
  839.     template : constant argument_ptr := new argument(prolog_list);
  840.     matched : boolean := true;
  841.   begin
  842.     if list1 = null then
  843.       if list2 = null then
  844.     matched := true;
  845.       else
  846.     matched := false;
  847.       end if;
  848.     end if;
  849.     while (list1 /= null) and matched loop
  850.       if list2 = null then
  851.     matched := false;
  852.       else
  853.     unify_arg(list1.elt, list2.elt, res_level, level, bindings, matched);
  854.     if matched then
  855.       if list1.has_tail then
  856.         if list2.has_tail then
  857.           unify_arg(list1.tail,list2.tail,res_level,level,bindings,matched);
  858.         else
  859.           template.list := list2.next_elt;
  860.           unify_arg(list1.tail,template,res_level,level,bindings,matched);
  861.         end if;
  862.         exit;
  863.       elsif list2.has_tail then
  864.         template.list := list1.next_elt;
  865.         unify_arg(template,list2.tail,res_level,level,bindings,matched);
  866.         exit;
  867.       else
  868.         list1 := list1.next_elt;
  869.         list2 := list2.next_elt;
  870.       end if;
  871.     end if;
  872.       end if;
  873.     end loop;
  874.     if matched and (list1 = null) and (list2 /= null) then
  875.       matched := false;
  876.     end if;
  877.     unified := matched;
  878.   end unify_list;
  879.  
  880.  
  881. procedure unify_arg(arg_node1, arg_node2 : AST_ptr; res_level, level : natural;
  882.         bindings : in out binding_list; unified : out boolean) is
  883.     temp_1, temp_2 : argument_ptr;
  884.   begin
  885.     case arg_node1.node_type is
  886.       when character_lit =>
  887.     temp_1 := new argument'(character_lit, null, arg_node1.char);
  888.       when variable =>
  889.     temp_1 := new argument'(variable, null, arg_node1.var_name);
  890.       when integer_num =>
  891.     temp_1 := new argument'(integer_num, null, arg_node1.int_num);
  892.       when float_num =>
  893.     temp_1 := new argument'(float_num, null, arg_node1.fp_num);
  894.       when fuzzy_value =>
  895.     temp_1 := new argument'(float_num, null, arg_node1.fuzzy_num);
  896.       when predicate =>
  897.     temp_1 := new argument'(predicate, null, arg_node1.name,
  898.                 arg_node1.p_arguments);
  899.       when others =>
  900.     error(no_pointer, "invalid node to unify");
  901.       end case;
  902.     case arg_node2.node_type is
  903.       when character_lit =>
  904.     temp_2 := new argument'(character_lit, null, arg_node2.char);
  905.       when variable =>
  906.     temp_2 := new argument'(variable, null, arg_node2.var_name);
  907.       when integer_num =>
  908.     temp_2 := new argument'(integer_num, null, arg_node2.int_num);
  909.       when float_num =>
  910.     temp_2 := new argument'(float_num, null, arg_node2.fp_num);
  911.       when fuzzy_value =>
  912.     temp_2 := new argument'(float_num, null, arg_node2.fuzzy_num);
  913.       when predicate =>
  914.     temp_2 := new argument'(predicate, null, arg_node2.name,
  915.                 arg_node2.p_arguments);
  916.       when others =>
  917.     error(no_pointer, "invalid node to unify");
  918.       end case;
  919.     unify_arg(temp_1, temp_2, level, level, bindings, unified);
  920.   end unify_arg;
  921.  
  922.  
  923. procedure unify_arg(arg1, arg2 : argument_ptr; res_level, level : natural;
  924.         bindings : in out binding_list; unified : out boolean) is
  925.     value1, value2 : argument_ptr;
  926.     level1, level2 : natural;
  927.     template1, template2 : AST_ptr := new AST'(predicate, null, null);
  928.   begin
  929.     lookup(arg1, res_level, bindings, value1, level1);
  930.     lookup(arg2, level, bindings, value2, level2);
  931.     if (value1.is_a = variable) then
  932.       if value1.v_name /= null then -- not anonymous
  933.     if not ( (value2.is_a = variable) and then (value2.v_name = null) ) then
  934.           bindings := new binding'(value1.v_name,level1,value2,level2,bindings);
  935.     end if;
  936.       end if;
  937.       unified := true;
  938.     elsif value2.is_a = variable then
  939.       if value2.v_name /= null then -- not anonymous
  940.         bindings := new binding'(value2.v_name, level2, value1, level1, bindings);
  941.       end if;
  942.       unified := true;
  943.     elsif value1.is_a = value2.is_a then
  944.       case value1.is_a is
  945.         when character_lit =>
  946.       unified := (value1.char = value2.char);
  947.         when predicate =>                                   -- unify functors
  948.           if value1.name.name = value2.name.name then -- there's a chance
  949.         template1.name := value1.name;
  950.         template1.p_arguments := value1.p_arguments;
  951.         template2.name := value2.name;
  952.         template2.p_arguments := value2.p_arguments;
  953.         unify(template1, template2, level1, level2, bindings, unified);
  954.       else
  955.         unified := false;
  956.       end if;
  957.         when float_num =>
  958.       unified := (value1.fp_num = value2.fp_num);
  959.         when integer_num =>
  960.       unified := (value1.int_num = value2.int_num);
  961.         when prolog_list =>
  962.           unify_list(value1.list, value2.list, level1, level2, bindings, unified);
  963.         when variable => -- something is seriously wrong
  964.       error(no_pointer, "System error in Unify_Arg");
  965.       unified := false;
  966.       end case;
  967.     else
  968.       unified := false;
  969.     end if;
  970.   end unify_arg;
  971.  
  972. end prover;
  973.